package com.heima.admin.service.impl;

import ch.qos.logback.core.joran.util.beans.BeanUtil;
import com.alibaba.fastjson.JSONArray;
import com.heima.admin.mapper.AdChannelMapper;
import com.heima.admin.mapper.AdSensitiveMapper;
import com.heima.admin.service.WemediaNewsAutoScanService;
import com.heima.aliyun.GreenImageScan;
import com.heima.aliyun.GreenTextScan;
import com.heima.common.constants.wemedia.WemediaConstants;
import com.heima.common.exception.CustException;
import com.heima.feigns.ArticleFeign;
import com.heima.feigns.WemediaFeign;
import com.heima.model.admin.pojos.AdChannel;
import com.heima.model.article.dtos.ArticleDto;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.utils.common.SensitiveWordUtil;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.lang.reflect.Array;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class WemediaNewsAutoScanServiceImpl implements WemediaNewsAutoScanService {
    /**
     * 自动审核的方法
     * @param wmNewsId
     */

    @Autowired
    WemediaFeign wemediaFeign;
    @Value("${file.oss.web-site}")
    String webSite;
//    @GlobalTransactional(rollbackFor = Exception.class)
    @Override
    public void autoScanByMediaNewsId(Integer wmNewsId) throws Exception {
        //1.1检查参数
        if (wmNewsId==null) {
            log.error("自动审核文章失败   文章的id值为空！");
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID);
        }
        //根据文章id远程调用feign
        ResponseResult<WmNews> wmNewsResult = wemediaFeign.findById(wmNewsId);
        if (wmNewsResult.getCode().intValue()!=0){
            log.error("自动审核失败 远程查询文章信息失败 原因：{}",wmNewsResult.getErrorMessage());
            CustException.cust(AppHttpCodeEnum.REMOTE_SERVER_ERROR);
        }
        WmNews wmNews = wmNewsResult.getData();
        if (wmNews==null) {
            log.error("自动审核文章失败，未查询到自媒体文章信息 wmNewsId{}",wmNewsId);
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        //判断文章的状态是否是4或者是8（即审核通过的状态）
        Short wmNewsStatus = wmNews.getStatus();
        if((wmNewsStatus== WmNews.Status.ADMIN_SUCCESS.getCode() ||wmNewsStatus==WmNews.Status.SUCCESS.getCode())
           && wmNews.getPublishTime().getTime() <= System.currentTimeMillis()){
            publishArticle(wmNews);
            return;
        }
        //判断文章的状态的值是否是1（1表示待审核）
        if (wmNewsStatus == WmNews.Status.SUBMIT.getCode()){
            //进行审核之前首先要抽取出文章中所有的文本内容和所有图片的url
            Map<String,Object> map = handleTextAndImages(wmNews);
            //敏感词审核  如果审核不通过 则将文章的状态修改为2
             boolean isSensitive = handleSensitive((String)map.get("content"),wmNews);
             if (!isSensitive) return;
            //阿里云的文本审核 失败 将文章的状态修改为2，如果不确定则将状态修改为3
            boolean isTextScan = handleTextScan((String)map.get("content"),wmNews);
            if (!isTextScan) return;
            //阿里云的图片审核 失败 将文章的状态修改为2，如果不确定则将状态修改为3
            Object images = map.get("images");
            if (images!=null){
                boolean isImagesScan = handleImageScan((List<String>)images,wmNews);
                if (!isImagesScan) return;
                //判断文章的发布时间是否大于当前时间 是 将状态修改为8
            }
            if (wmNews.getPublishTime().after(new Date())){
                updateWmNews(wmNews,WmNews.Status.SUCCESS.getCode(),"审核成功");
                return;
            }
            //发布文章
            publishArticle(wmNews);

        }

    }
    @Autowired
    GreenImageScan greenImageScan;

    /**
     * 阿里云的图片审核
     * @param images
     * @return
     */
    private boolean handleImageScan(List<String> images,WmNews wmNews) {
        boolean flag = true;
        try {
            Map map = greenImageScan.imageUrlScan(images);
           String suggestion=(String) map.get("suggestion");
           switch (suggestion){
               case "block":
                 updateWmNews(wmNews,WmNews.Status.FAIL.getCode(),"图片内容涉嫌违规，审核失败！");
                 flag=false;
                 break;
               case "review":
                   updateWmNews(wmNews,WmNews.Status.ADMIN_AUTH.getCode(),"图片中有不确定因素，转为人工审核");
                   flag=false;
                   break;


           }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("阿里云图片审核服务异常 原因{}",e.getMessage());
            updateWmNews(wmNews,WmNews.Status.ADMIN_AUTH.getCode(),"阿里云图片审核出现异常，转为人工审核！");
            flag=false;

        }

        return flag;
    }


    @Autowired
    GreenTextScan greenTextScan;
    /**
     *此方法为阿里云的文本检测
     * @param content
     * @param wmNews
     * @return
     */

    private boolean handleTextScan(String content, WmNews wmNews)  {
        boolean flag = true;
        try {
            Map map = greenTextScan.greenTextScan(content);
             String suggestion = (String) map.get("suggestion");//根据这个字段对应的值就可以判断其审核的状态
             switch (suggestion){
                 case "block":
                     updateWmNews(wmNews,WmNews.Status.FAIL.getCode(),"文本内容中有违规内容，审核不通过！");
                     flag=false;
                     break;
                 case "review":
                     updateWmNews(wmNews,WmNews.Status.ADMIN_AUTH.getCode(),"文本中有不确定因素，转为人工服务！");
                     flag=false;
                     break;
             }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("阿里云服务异常！原因：{}",e.getMessage());
            updateWmNews(wmNews,WmNews.Status.ADMIN_AUTH.getCode(),"阿里云服务异常，转为人工审核！");
            flag=false;
        }


        return flag;
    }

    //注入mapper
    @Autowired
    AdSensitiveMapper adSensitiveMapper;

    /**
     * 基于DFA检测内容是否包含敏感词
     * @param content
     * @param wmNews
     * @return
     */
    private boolean handleSensitive(String content, WmNews wmNews) {
        boolean flag = true;
       //1.查询出数据库中的敏感词
        List<String> sensitives = adSensitiveMapper.findAllSensitives();
       //2.查询到敏感词之后，需要将敏感词集合转化为DFA数据模型
        SensitiveWordUtil.initMap(sensitives);
       //3.检测敏感词
        Map<String, Integer> resultMap = SensitiveWordUtil.matchWords(content);
        if (resultMap!=null && resultMap.size()>0){
            //说明此时文章是包含敏感词的，将文章的状态修改为2
            updateWmNews(wmNews,WmNews.Status.FAIL.getCode(),"内容中包含敏感词"+resultMap);
            flag=false;
        }



        return flag;

    }

    /**
     * 修改文章的状态
     * @param wmNews
     * @param status
     * @param  reason
     */
    private void updateWmNews(WmNews wmNews, short status, String reason) {
        wmNews.setStatus(status);
        wmNews.setReason(reason);
        ResponseResult responseResult = wemediaFeign.updateWmNews(wmNews);
        if (responseResult.getCode().intValue()!=0){
            log.error("远程电泳修改自媒体文章接口出错，原因：{}",responseResult.getErrorMessage());
            CustException.cust(AppHttpCodeEnum.REMOTE_SERVER_ERROR,responseResult.getErrorMessage());
        }

    }

    /**
     * 抽取出文章中所有的文本内容和所有图片的url
     * @param wmNews  content type:text  title
     * @return
     */
    private Map<String, Object> handleTextAndImages(WmNews wmNews) {
        String content = wmNews.getContent();//得到的内容是一个数组形式，里面可能既有文本也有图片
        if (StringUtils.isBlank(content)) {
            log.error("自动审核文章失败，文章内容为空！");
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST,"文章的内容为空");
        }
        List<Map> contentMaps = JSONArray.parseArray(content, Map.class);
        //1.抽取文章中所有的文本信息
        String ContentStr = contentMaps.stream()
                .filter(map -> "text".equals(map.get("type")))
                .map(map -> (String) map.get("value"))
                .collect(Collectors.joining("_hmtt_"));
        ContentStr=ContentStr+"_hmtt_"+wmNews.getTitle();//将标题拼接到内容字符串中
        //2.抽取文章所有的图片信息（图片一般分布在文章内容中（全路径）或者是images中（要加上前缀才能审核））
        List<String> imageList = contentMaps.stream()
                .filter(map -> "image".equals(map.get("type")))
                .map(map -> (String) map.get("value"))
                .collect(Collectors.toList());
        if (StringUtils.isNotBlank(wmNews.getImages())) {
        //按照 逗号 切割封面字符串 得到数组 基于数组得到stream 将每一条数据都拼接一个前缀 收集成集合
            List<String> list = Arrays.stream(wmNews.getImages().split(","))
                    .map(url -> webSite + url)
                    .collect(Collectors.toList());
            imageList.addAll(list);

        }
        //去重
        imageList=imageList.stream().distinct().collect(Collectors.toList());
         Map resultMap = new HashMap<>();
        resultMap.put("content",ContentStr);
        resultMap.put("images",imageList);
        return resultMap;
    }

    /**
     * 发布文章的方法
     * @param wmNews
     */
    private void publishArticle(WmNews wmNews) {
     //1.远程调用articleFeign接口 保存3张表的数据 保存成功获取返回的articleId
         Long articleId = saveArticle(wmNews);
     //2.修改wmNews 设置和article的关联  修改状态为9
       wmNews.setArticleId(articleId);
       updateWmNews(wmNews,WmNews.Status.PUBLISHED.getCode(),"发布成功！");
    }
    @Autowired
    AdChannelMapper adChannelMapper;
    @Autowired
    ArticleFeign articleFeign;

    /**
     * 通过远程调用articleFeign接口保存三张表的信息
     * @param wmNews
     * @return
     */
    private Long saveArticle(WmNews wmNews) {
    //封装articleDto
        ArticleDto articleDto = new ArticleDto();
    //拷贝属性
        BeanUtils.copyProperties(wmNews,articleDto);
        articleDto.setId(wmNews.getArticleId());
        articleDto.setFlag((byte)0);//表示是普通文章
        articleDto.setLayout(wmNews.getType());//布局
        articleDto.setWmUserId(wmNews.getUserId());//用于获取作者信息
        AdChannel channel = adChannelMapper.selectById(wmNews.getChannelId());
        articleDto.setChannelName(channel.getName());
        ResponseResult<Long> responseResult = articleFeign.saveArticle(articleDto);
        if (responseResult.getCode()!=0) {
            log.error("远程调用失败！");
            CustException.cust(AppHttpCodeEnum.REMOTE_SERVER_ERROR,"远程调用失败！");
        }
        return responseResult.getData();




    }
}
